﻿// ****************************************************************
// Copyright 2012, Stephan Burguchev
// e-mail: me@sburg.net
// ****************************************************************
// *
using System;
using System.Diagnostics;
using System.Threading;
using System.Windows;
using System.Windows.Input;
using System.Windows.Threading;

namespace Updater.Wpf.Utils
{
    /// <summary>
    ///     A base class for command implementations.
    /// </summary>
    public abstract class Command : ICommand
    {
        private readonly Dispatcher dispatcher;

        /// <summary>
        ///     Constructs an instance of <c>CommandBase</c>.
        /// </summary>
        protected Command()
        {
            if (Application.Current != null)
            {
                this.dispatcher = Application.Current.Dispatcher;
            }
            else
            {
                // this is useful for unit tests where there is no application running
                this.dispatcher = Dispatcher.CurrentDispatcher;
            }

            Debug.Assert(this.dispatcher != null);
        }

        /// <summary>
        ///     Occurs whenever the state of the application changes such that the result of a call to
        ///     <see cref="CanExecute" /> may return a different value.
        /// </summary>
        public event EventHandler CanExecuteChanged
        {
            add
            {
                CommandManager.RequerySuggested += value;
            }
            remove
            {
                CommandManager.RequerySuggested -= value;
            }
        }

        /// <summary>
        ///     Determines whether this command can execute.
        /// </summary>
        /// <param name="parameter">
        ///     The command parameter.
        /// </param>
        /// <returns>
        ///     <see langword="true" /> if the command can execute, otherwise <see langword="false" />.
        /// </returns>
        public abstract bool CanExecute(object parameter);

        /// <summary>
        ///     Executes this command.
        /// </summary>
        /// <param name="parameter">
        ///     The command parameter.
        /// </param>
        public abstract void Execute(object parameter);

        /// <summary>
        ///     Raises the <see cref="CanExecuteChanged" /> event.
        /// </summary>
        protected virtual void OnCanExecuteChanged()
        {
            if (!this.dispatcher.CheckAccess())
            {
                this.dispatcher.Invoke((ThreadStart)this.OnCanExecuteChanged, DispatcherPriority.Normal);
            }
            else
            {
                CommandManager.InvalidateRequerySuggested();
            }
        }
    }
}
